package logic.ships.drone;

import map.asteroids.ResourceAsteroid;
import networking.messages.createMessages.ShipType;
import networking.messages.syncMessages.NodeSyncMessage;
import networking.messages.syncMessages.ValueType;

import com.jme.math.Vector3f;
import com.jme.scene.Node;

import logic.common.player.Player;
import logic.common.team.Team;
import logic.nodes.collision.DummyType;
import logic.ships.moveableShip.MovableShip;
import logic.ships.resourceShip.ResourceShip;
import logic.ships.resourceShip.ResourceSlot;

public class Drone extends MovableShip {
	
	private static final long serialVersionUID = 1L;
	
	private ResourceAsteroid currentAsteroid;
	private ResourceShip currentResourceShip;
	private ResourceSlot currentResourceSlot;
	
	private DroneProperties droneProps;
	private DroneController droneController;
		
	private Vector3f targetLocation;
	private boolean isHarvesting;
	
	public Drone(String modelPath, String title, Node model, DroneProperties droneProps, Team team) {
		this(modelPath, title, model, droneProps, team, DummyType.None);
	}
	
	public Drone(String modelPath, String title, Node model, DroneProperties droneProps, Team team, 
			DummyType dummyType) {
		super(modelPath, title, model, droneProps, team, dummyType);
		this.droneProps = droneProps;
		
		if(dummyType == DummyType.None) {
			createMoveForwardController();
			currentResourceShip = team.getMotherShip();
		}
	}
	
	@Override
	protected void applyDummyType() {
		super.applyDummyType();
		
		if(dummyType == DummyType.None) {
			isHarvesting = true;
			
			droneController = new DroneController(this);
			addController(droneController);
		}
	}
	
	@Override
	protected void initValueContainer() {
		super.initValueContainer();
		valueManager.changeValue(ValueType.Load, 0f);
	}
	
	private void changeLoad(float newLoad) {
		assert(newLoad >= 0);
		
		if(getCurrentLoad() == newLoad) return;
		
		valueManager.changeValue(ValueType.Load, newLoad);
	}
	
	@Override
	public void destroy() {
		if(!shooters.isEmpty()) {
			Player lastShooter = shooters.get(0);
			if(lastShooter != null) team.removeDrone(this, lastShooter);
		} else team.removeDrone(this);
		
		super.destroy();
	}
	
	public void drop() {
		assert(currentResourceShip != null);
		
		isHarvesting = false;
		currentResourceSlot = currentResourceShip.getNearestResourceSlot(getLocalTranslation());
		targetLocation = currentResourceSlot.getMoveLocation();
		moveForwardController.stop(false);
	}
	
	public void harvestAsteroid(ResourceAsteroid asteroid) {
		if(asteroid == null) {
			targetLocation = null;
			isHarvesting = false;
			currentAsteroid = null;
			moveForwardController.stop(true);
		} else {
			targetLocation = asteroid.getLocalTranslation();
			currentResourceShip = team.getShipAtField(asteroid.getAsteroidField());
			isHarvesting = true;
			currentAsteroid = asteroid;
			moveForwardController.stop(false);
		}
	}
	
	public ResourceAsteroid getCurrentAsteroid() { return currentAsteroid; }
	
	public ResourceShip getCurrentResourceShip() { return currentResourceShip; }
	
	public Vector3f getTargetLocation() { return targetLocation; }
	
	public boolean isHarvesting() { return isHarvesting; }
	
	public float getHarvestSpeed() { return droneProps.getHarvestSpeed(); }
	
	public float getDropSpeed() { return droneProps.getDropSpeed(); }
	
	public float getRepairSpeed() { return droneProps.getRepairSpeed(); }
	
	public int getMaxLoad() { return droneProps.getMaxLoad(); }
	
	public float getCurrentLoad() { return valueManager.getFloatValue(ValueType.Load); }
	
	public boolean loadIsEmpty() { return getCurrentLoad() == 0f; }
	
	public boolean isFullyLoaded() { return getCurrentLoad() == getMaxLoad(); }
	
	public DroneProperties getDroneProperties() { return droneProps; }
	
	public void setDroneProperties(DroneProperties props) { droneProps = props; }
	
	public void harvest(float amount) {
		float currentLoad = getCurrentLoad();
		if(currentLoad + amount > getMaxLoad()) amount = getMaxLoad() - currentLoad;
		changeLoad(currentLoad + amount);
		currentAsteroid.harvest(amount);
	}
	
	public ResourceAsteroid getAsteroid() { return currentAsteroid; }
	
	public void drop(float amount) {
		float currentLoad = getCurrentLoad();
		assert(amount > 0f && currentLoad >= 0f);
		if(currentLoad - amount < 0f) amount = currentLoad;
		if(amount == 0f) return;
		
		changeLoad(currentLoad - amount);
		currentResourceShip.dropResource(amount);
	}
	
	@Override
	public int getDestroyMoney() { return 100; }

	@Override
	protected float getDistanceFactor() { return 0.25f; }
	
	public DroneController getDroneController() { return droneController; }
	
	@Override
	protected ShipType getShipType() { return ShipType.Drone; }
	
	@Override
	public boolean applySyncMessage(NodeSyncMessage shipSyncMessage) {
		if(super.applySyncMessage(shipSyncMessage)) return true;
		if(shipSyncMessage.getType() == ValueType.Load) {
			changeLoad(shipSyncMessage.getFloatValue());
			return true;
		}
		
		return false;
	}
}